/*
 * @Author: xiaosihan
 * @Date: 2023-07-13 17:30:11
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-12-15 19:10:42
 */

import {
  AmbientLight,
  BackSide,
  DirectionalLight,
  FrontSide,
  MeshStandardMaterial,
  Object3D,
  PointLight,
  SRGBColorSpace,
  Vector2,
  Vector3,
} from 'three';
import ThreeBase from 'three-base';
import MeshBase from 'three-base/MeshBase';
import SpriteText from 'three-base/SpriteText';
import threeUtils from 'three-base/threeUtils';
import Transition from 'three-base/Transition';

// 商品渲染器
class GoodsRenderer extends ThreeBase {
  constructor() {
    super();
    window.goodsRenderer = this;
    this.setCameraType('orthographicCamera');
  }

  // 环境光
  ambientLight = (() => {
    const ambientLight = new AmbientLight('#fff', 1.2);
    this.scene.add(ambientLight);
    return ambientLight;
  })();

  // 点光源1
  pointLight1 = (() => {
    const pointLight1 = new PointLight('#fff', 1.2);
    pointLight1.distance = 1000;
    pointLight1.decay = 0;
    pointLight1.position.set(10, 10, 10);
    this.scene.add(pointLight1);
    return pointLight1;
  })();

  // 方向光
  directionalLight = (() => {
    const directionalLight = new DirectionalLight('#fff', 1);
    directionalLight.position.set(-10, 10, 5);
    directionalLight.target.position.set(0, 0, 0);
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.set(1024, 1024);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  // 方向光2
  directionalLight2 = (() => {
    const directionalLight = new DirectionalLight('#fff', 1);
    directionalLight.position.set(10, 10, -5);
    directionalLight.target.position.set(0, 0, 0);
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.set(1024, 1024);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  init() {
    this.gridHelper.visible = false;
    this.axesHelper.visible = false;
    super.init();
    // 不自动渲染
    this.autoRender = false;
    this.needRender = true;
    this.renderer.outputColorSpace = SRGBColorSpace;

    this.orthographicCamera.far = 5010;
    this.orthographicCamera.near = 4990;
    this.orthographicCamera.updateProjectionMatrix();

    this.resetLookAt({
      center: new Vector3(0, 0, 0),
      position: new Vector3(0, 0, 10),
    });
  }

  // 设置尺寸
  setSize(width: number, height: number) {
    const { left, right, top, bottom } = this.orthographicCamera;
    super.setSize(width, height);
    Object.assign(this.orthographicCamera, { left, right, top, bottom });
  }

  // 弹窗文本
  spriteText = (() => {
    const spriteText = new SpriteText('123');
    spriteText.color = '#ff0000';
    spriteText.material.depthTest = false;
    spriteText.renderOrder = 1;
    spriteText.scale.multiplyScalar(0.03);
    spriteText.visible = false;
    this.scene.add(spriteText);
    return spriteText;
  })();

  // 过度动画
  transtion = (() => {
    const transtion = new Transition({ zoom: 1 });
    transtion.onChange(({ zoom }) => {
      this.orthographicCamera.zoom = zoom;
    });
    return transtion;
  })();

  // 设置默认视角
  setDefaultLookAt() {
    this.storeName = '';
    this.transtion.reset({ zoom: this.orthographicCamera.zoom }).set({ zoom: 1 });
    this.setLookAt({
      center: new Vector3(0, 0, 0),
      position: new Vector3(0, 0, 7),
    });
  }

  // 衣服模型(正面)
  frontCloth = (() => {
    const frontCloth = new MeshBase();
    frontCloth.addEventListener('loaded', async () => {
      threeUtils.scaleTo(frontCloth, 10, ['x', 'y']);
      threeUtils.center(frontCloth);
      await frontCloth.traverseMesh((mesh) => {
        const material = (mesh.material as MeshStandardMaterial).clone();
        mesh.material = material;
        material.color.set('#ffffff');
        material.metalness = 0;
        material.roughness = 0.8;
        material.side = FrontSide;

        if ((mesh.material as MeshStandardMaterial).map) {
          (mesh.material as MeshStandardMaterial).map!.colorSpace = SRGBColorSpace;
        }

        // three事件
        mesh.userData = {
          cursor: 'pointer',
          enableEvent: true,
        };

        mesh.addEventListener('mouseenter', () => {
          this.spriteText.text = `${mesh.name}\n\n`;
          this.spriteText.scale.multiplyScalar(0.03);
          this.spriteText.visible = true;
          this.needRender = true;
        });

        mesh.addEventListener('mousemove', (e) => {
          this.spriteText.position.copy((e as any).point);
          this.needRender = true;
        });
        mesh.addEventListener('mouseleave', () => {
          this.spriteText.visible = false;
          this.needRender = true;
        });
      });

      this.needRender = true;
      this.scene.add(frontCloth);
    });
    return frontCloth;
  })();

  // 衣服模型(反面)
  backCloth = (() => {
    const backCloth = new MeshBase();
    backCloth.addEventListener('loaded', async () => {
      threeUtils.scaleTo(backCloth, 10, ['x', 'y']);
      threeUtils.center(backCloth);
      await backCloth.traverseMesh((mesh) => {
        const material = (mesh.material as MeshStandardMaterial).clone();
        mesh.material = material;
        material.color.set('#ffffff');
        material.metalness = 0;
        material.roughness = 0.8;
        material.side = BackSide;
      });
      this.needRender = true;
      this.scene.add(backCloth);
    });
    return backCloth;
  })();

  // 加载衣服模型
  async loadModal(url: string) {
    await this.frontCloth.loadModel(url);
    await this.backCloth.loadModel(url);

    // 更具模型大小调节相机的参数
    const frontSize = threeUtils.getSize(this.frontCloth);
    const sideLength = Math.max(frontSize.x, frontSize.y, frontSize.z);
    const rendererSize = this.renderer.getSize(new Vector2());
    this.setOrthographicCameraView(
      (rendererSize.x / Math.min(rendererSize.x, rendererSize.y)) * sideLength,
      (rendererSize.y / Math.min(rendererSize.x, rendererSize.y)) * sideLength,
    );
  }

  //清除模型
  clear() {
    this.frontCloth.clear();
    this.backCloth.clear();
  }

  // 设置
  storeName = '';

  // 预设的相机位置
  cameraPosition?: { x: number; y: number; z: number };

  setStoreName(name: string, cameraPosition?: { x: number; y: number; z: number }) {
    this.storeName = name;
    this.cameraPosition = cameraPosition;
    this.needRender = true;
  }

  // 设置正交相机的视角哦
  setOrthographicCameraView(width: number, height: number) {
    this.orthographicCamera.left = width * -0.5 * 1.1;
    this.orthographicCamera.top = height * 0.5 * 1.1;
    this.orthographicCamera.right = width * 0.5 * 1.1;
    this.orthographicCamera.bottom = height * -0.5 * 1.1;
    this.orthographicCamera.updateProjectionMatrix();
  }

  // 查看对象
  lookat_object?: Object3D = undefined;

  async lookatObject(obj: Object3D) {
    if (this.lookat_object !== obj) {
      this.lookat_object = obj;
      const size = threeUtils.getSize(this.lookat_object);
      const center = threeUtils.getCenter(this.lookat_object);
      const modelSize = size.length() * 1.4;
      const cameraDistance = modelSize / (2 * Math.tan((60 * Math.PI) / 360));
      const position = center.clone();
      if (this.cameraPosition) {
        const { x, y, z } = this.cameraPosition;
        position.set(x, y, z);
      } else {
        position.x +=
          Math.sign(center.x) * (Math.abs(center.x) > Math.abs(center.z) ? cameraDistance : 0);
        position.z +=
          Math.sign(center.z + 0.5) *
          (Math.abs(center.z) > Math.abs(center.x) ? cameraDistance : 0);
      }
      await this.setLookAt({ center, position });
      this.needRender = true;
    }
  }

  // 渲染
  render(): void {
    this.pointLight1.position.copy(this.orthographicCamera.position).setLength(50);

    this.frontCloth.traverseMesh((mesh) => {
      if (this.storeName && mesh.name === this.storeName && this.frontCloth.loaded) {
        (mesh.material as MeshStandardMaterial).color.set('#aaffaa');
        this.lookatObject(mesh);
      } else {
        (mesh.material as MeshStandardMaterial).color.set('#ffffff');
      }
    });

    super.render();
  }
}

const goodsRenderer = new GoodsRenderer();

export default goodsRenderer;
